package com.wangzz.mallchat.common.user.service.impl;

import cn.hutool.core.util.StrUtil;
import com.wangzz.mallchat.common.common.constant.RedisKey;
import com.wangzz.mallchat.common.common.utils.JwtUtils;
import com.wangzz.mallchat.common.common.utils.RedisUtils;
import com.wangzz.mallchat.common.user.service.LoginService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {

    public static final int TOKEN_EXPIRE_DAYS = 3;
    public static final int TOKEN_RENEWAL_DAYS = 1;
    @Autowired
    private JwtUtils jwtUtils;

    @Override
    @Async // 对spring代理中的方法做的包装，检测到async注解，将方法提交到线程池，让线程池其他线程去执行
    public void renewalTokenIfNecessary(String token) {
        // 获取有效uid
        Long validUid = getValidUid(token);
        // 获取tokenKey
        String tokenKey = getRedisTokenKey(validUid);
        // 判断token是否过期
        Long expire = RedisUtils.getExpire(tokenKey, TimeUnit.DAYS);
        if (expire == -2) {
            // token不存在，让他重新登录
            return;
        }
        if (expire < TOKEN_RENEWAL_DAYS) {
            // token过期了，续期
            RedisUtils.expire(getRedisTokenKey(validUid), TOKEN_EXPIRE_DAYS, TimeUnit.DAYS);
        }
    }

    /**
     * 登录
     *
     * @param uid
     * @return token
     */
    @Override
    public String login(Long uid) {
        String key = getRedisTokenKey(uid);
        String token = RedisUtils.getStr(key);
        if (StrUtil.isNotBlank(token)) {
            return token;
        }
        token = jwtUtils.createToken(uid);
        // 分布式存储token，设置过期时间为3天
        RedisUtils.set(key, token, TOKEN_EXPIRE_DAYS, TimeUnit.DAYS);
        return token;
    }

    /**
     * 校验token是否有效
     *
     * @param token
     * @return uid
     */
    @Override
    public Long getValidUid(String token) {
        // 存在问题旧token校验通过情况
        // 解析token
        Long uid = jwtUtils.getUidOrNull(token);
        if (Objects.isNull(uid)) {
            return null;
        }
        // 从redis中获取token 校验是否过期
        String oldToken = RedisUtils.getStr(getRedisTokenKey(uid));
        if (StringUtils.isBlank(oldToken)) {
            return null;
        }
        // 解决
        return Objects.equals(token, oldToken) ? uid : null;
    }

    private String getRedisTokenKey(Long uid) {
        return RedisKey.getKey(RedisKey.USER_TOKEN_KEY, uid);
    }
}
